package com.jxtc.enterprise.admin.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.admin.dto.StoreWithTenantDTO;
import com.jxtc.enterprise.admin.vo.AdminAssignableStoreVO;
import com.jxtc.enterprise.common.entity.Food;
import com.jxtc.enterprise.common.entity.Store;
import com.jxtc.enterprise.common.entity.TenantStore;
import com.jxtc.enterprise.common.exception.ModifyFailureException;
import com.jxtc.enterprise.common.mapper.FoodMapper;
import com.jxtc.enterprise.common.mapper.StoreMapper;
import com.jxtc.enterprise.common.mapper.TenantStoreMapper;
import com.jxtc.enterprise.common.service.FoodService;
import com.jxtc.enterprise.common.service.TenantStoreService;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class AdminTenantStoreService {

    private final StoreMapper storeMapper;
    private final FoodService commonFoodService;
    private final FoodMapper foodMapper;
    private final TenantStoreMapper tenantStoreMapper;
    private final TenantStoreService tenantStoreService;

    /**
     * 分页查询可分配给指定租户的的店铺列表，store表中的属于租户直属的，此处分配的是属于其他租户的店铺，步骤如下
     * （1）查询 store 表，查询出不属于 租户 的有效店铺 list1 ==> select id from store where tenant_id != 'xxx' and del_flag = 0;
     * （2）查询 tenant_store_t 租户-店铺 授权关系表，找出租户已经被授权的店铺 list2 ==> select store_id from tenant_store_t where tenant_id = 'xxx' and del_flag = 0;
     * （3）list1 中提出 list2 即为可以授权给租户的店铺列表
     *
     * @param pageNo       当前页码
     * @param pageSize     每页数据数量
     * @param storeKeyword 店铺查询关键字
     * @param tenantId     指定租户 ID
     * @return 店铺信息列表
     */
    public PaginationResponseVO<AdminAssignableStoreVO> queryCanAssignableStores(int pageNo, int pageSize, String storeKeyword, String tenantId) {
        // 构造分页对象
        Page<StoreWithTenantDTO> page = new Page<>(pageNo, pageSize);

        Page<StoreWithTenantDTO> result = storeMapper.queryCanAssignableStores(page, storeKeyword, tenantId);
        List<AdminAssignableStoreVO> records = result.getRecords().stream()
                .map(this::buildAssignableStoreVO)
                .collect(Collectors.toList());

        // 构造分页响应对象
        return new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);
    }

    private AdminAssignableStoreVO buildAssignableStoreVO(StoreWithTenantDTO dto) {
        AdminAssignableStoreVO vo = new AdminAssignableStoreVO();
        vo.setStoreId(dto.getStoreId());
        vo.setStoreName(dto.getStoreName());
        vo.setMerchantName(dto.getMerchantName());
        vo.setPhone(dto.getPhone());
        vo.setAddress(dto.getAddress());
        vo.setTenantName(dto.getTenantName());

        return vo;
    }


    /**
     * 批量将店铺绑定给指定的租户，保存错误时抛出 ModifyFailureException 异常并回滚数据
     *
     * @param storeIds 店铺 ID 列表
     * @param tenantId 指定租户
     */
    @Transactional(rollbackFor = ModifyFailureException.class)
    public void assignStoresToTenant(List<String> storeIds, String tenantId) throws ModifyFailureException {

        // 1. 检查新添加的店铺是否已经被授权给了租户，正常情况下接口入参中的店铺不会包含已经授权的店铺，避免之前的bug引入的脏数据，此处做冗余检查
        // select * from tenant_store_t where tenant_id = #{tenantId} and del_flag = 0 and store_id in (xxx);
        List<TenantStore> duplicatedAuthorizedStores = tenantStoreMapper.selectList(
                new LambdaQueryWrapper<TenantStore>()
                        .eq(TenantStore::getTenantId, tenantId)
                        .eq(TenantStore::getDelFlag, 0)
                        .in(TenantStore::getStoreId, storeIds));

        // 2. 若请求授权的店铺已经在 tenant_store_t 表中，存在店铺与租户的授权关系，则仅对未添加授权关系的店铺，添加授权关系
        if (!CollectionUtils.isEmpty(duplicatedAuthorizedStores)) {
            List<String> duplicatedAuthorizedStoreIds = duplicatedAuthorizedStores.stream().map(TenantStore::getStoreId).collect(Collectors.toList());
            // 当请求授权的店铺中，某些店铺之前已经授权给了该租户，从入参店铺id列表中，剔除已经存在授权关系的店铺，将未授权的店铺进行授权，打印告警日志便于后期问题定位
            storeIds.removeAll(duplicatedAuthorizedStoreIds);
            log.warn("租户已经被授权 {} 店铺，剔除对已授权店铺的授权，仅对未授权的店铺 {} 添加授权关系",
                    duplicatedAuthorizedStoreIds, storeIds);
        }

        // 3. 批量向 tenant_store_t 表中添加授权关系记录
        List<TenantStore> authorizedStores = new ArrayList<>();
        for (int k = 0; k < storeIds.size(); k++) {
            String storeId = storeIds.get(k);
            TenantStore tenantStore = new TenantStore();
            tenantStore.setTenantId(tenantId);
            tenantStore.setStoreId(storeId);
            tenantStore.setDelFlag(false);
            tenantStore.setCreateTime(LocalDateTime.now());
            tenantStore.setUpdateTime(LocalDateTime.now());

            authorizedStores.add(tenantStore);
        }

        boolean savedBatch = tenantStoreService.saveBatch(authorizedStores);
        if (!savedBatch) {
            throw new ModifyFailureException("为租户 " + tenantId + " 批量授权店铺失败，请联系管理员排查");
        }
    }

    /**
     * 通过一条 store 记录生成一份新的 tenantId 不同的 store 记录
     */
    private Store buildStore(String tenantId, Store store) {
        Store newStore = new Store();
        newStore.setName(store.getName());
        newStore.setLogo(store.getLogo());
        newStore.setAddress(store.getAddress());
        newStore.setLongitude(store.getLongitude());
        newStore.setLatitude(store.getLatitude());
        newStore.setDescription(store.getDescription());
        newStore.setCategoryId(store.getCategoryId());
        newStore.setCategoryName(store.getCategoryName());
        newStore.setFoodTypes(store.getFoodTypes());
        newStore.setMerchantIdNum(store.getMerchantIdNum());
        newStore.setMerchantPhone(store.getMerchantPhone());
        newStore.setMerchantWechatNum(store.getMerchantWechatNum());
        newStore.setMerchantName(store.getMerchantName());
        newStore.setBusinessStart(store.getBusinessStart());
        newStore.setBusinessEnd(store.getBusinessEnd());
        newStore.setQualifications(store.getQualifications());
        newStore.setStorePrice(store.getStorePrice());
        newStore.setMerchantLoginPasswd(store.getMerchantLoginPasswd());
        newStore.setLimitCount(store.getLimitCount());
        newStore.setPrinterSn(store.getPrinterSn());
        newStore.setMergeFoodItems(store.getMergeFoodItems());
        newStore.setPrintLabelType(store.getPrintLabelType());
        newStore.setTenantId(tenantId);
        return newStore;
    }

    private Food buildFood(String storeId, Food food) {
        Food newFood = new Food();
        newFood.setName(food.getName());
        newFood.setImage(food.getImage());
        newFood.setDescription(food.getDescription());
        newFood.setSpecification(food.getSpecification());
        newFood.setStoreName(food.getStoreName());
        newFood.setSalePrice(food.getSalePrice());
        newFood.setStorePrice(food.getStorePrice());
        newFood.setLimitCount(food.getLimitCount());
        newFood.setFoodTypeName(food.getFoodTypeName());
        newFood.setStatus(food.getStatus());
        newFood.setSortFlag(food.getSortFlag());
        newFood.setRequired(food.getRequired());

        newFood.setStoreId(storeId);
        return newFood;
    }
}
